﻿using System.Drawing;

namespace KinonekoSoftware.Foundation.Styles
{

    public delegate T RGBColorFactory<T>(byte r, byte g, byte b);
    public delegate T ARGBColorFactory<T>(byte a ,byte r, byte g, byte b);
    
    public abstract class ThemeSystem
    {
        protected private void InitializeColors()
        {
            InitializeOverlayBrush(Colors);
            InitializeBackgroundBrush(Colors);
            InitializeForegroundBrush(Colors);
            InitializeAdaptiveBrush(Colors);
            InitializeNotificationBrush(Colors);
            InitializeHighlightBrush(Colors);
        }

        public static uint FromRGB(int r, int g, int b)
        {
            return 0xff000000 | (uint)((r & 0xff) << 16) | (uint)((g & 0xff) << 8) | (uint)((b & 0xff));
        }
        
        public static uint FromRGB(byte r, byte g, byte b)
        {
            return 0xff000000 | (uint)((r & 0xff) << 16) | (uint)((g & 0xff) << 8) | (uint)((b & 0xff));
        }
        
        public static uint FromARGB(byte a, byte r, byte g, byte b)
        {
            return (uint)((a & 0xff) << 24) | (uint)((r & 0xff) << 16) | (uint)((g & 0xff) << 8) | (uint)((b & 0xff));
        }
        
        public static uint FromARGB(int a, int r, int g, int b)
        {
            return (uint)((a & 0xff) << 24) | (uint)((r & 0xff) << 16) | (uint)((g & 0xff) << 8) | (uint)((b & 0xff));
        }

        public static void GetRGB(uint v, out byte r, out byte g, out byte b)
        {
            r = (byte)((v & 0x00ff0000) >> 16);
            g = (byte)((v & 0x0000ff00) >> 8);
            b = (byte)(v & 0xff);
        }
        
        public static void GetRGB<T>(uint v, RGBColorFactory<T> factory)
        {
            var r = (byte)((v & 0x00ff0000) >> 16);
            var g = (byte)((v & 0x0000ff00) >> 8);
            var b = (byte)(v & 0xff);
            factory?.Invoke(r, g, b);
        }
        
        public static void GetARGB(uint v, out byte a, out byte r, out byte g, out byte b)
        {
            a = (byte)((v & 0xff000000) >> 24);
            r = (byte)((v & 0x00ff0000) >> 16);
            g = (byte)((v & 0x0000ff00) >> 8);
            b = (byte)(v & 0xff);
        }
        
        public static void GetARGB<T>(uint v, ARGBColorFactory<T> factory)
        {
            var a = (byte)((v & 0xff000000) >> 24);
            var r = (byte)((v & 0x00ff0000) >> 16);
            var g = (byte)((v & 0x0000ff00) >> 8);
            var b = (byte)(v & 0xff);
            factory?.Invoke(a, r, g, b);
        }

        /// <summary>
        /// 初始化遮罩层
        /// </summary>
        /// <param name="colors">容器</param>
        protected abstract void InitializeOverlayBrush(Dictionary<BrushKey, uint> colors);

        /// <summary>
        /// 初始化提示色
        /// </summary>
        /// <param name="colors">容器</param>
        protected virtual void InitializeNotificationBrush(Dictionary<BrushKey, uint> colors)
        {
            colors.TryAdd(BrushKey.Error100, FromRGB(0xbb, 0x21, 0x24));
            colors.TryAdd(BrushKey.Error200, FromRGB(0xd9, 0x08, 0x0c));
            colors.TryAdd(BrushKey.Error300, FromRGB(0xA6, 0x06, 0x09));
            colors.TryAdd(BrushKey.Error400, FromRGB(0xec, 0x93, 0x94));

            colors.TryAdd(BrushKey.Warning100, FromRGB(0xdb, 0x94, 0x00));
            colors.TryAdd(BrushKey.Warning200, FromRGB(0xff, 0xb3, 0x14));
            colors.TryAdd(BrushKey.Warning300, FromRGB(0xa8, 0x72, 0x00));
            colors.TryAdd(BrushKey.Warning400, FromRGB(0xff, 0xd6, 0x80));

            colors.TryAdd(BrushKey.Info100, FromRGB(0x00, 0x7a, 0xcc));
            colors.TryAdd(BrushKey.Info200, FromRGB(0x00, 0x92, 0xf2));
            colors.TryAdd(BrushKey.Info300, FromRGB(0x00, 0x55, 0x8f));
            colors.TryAdd(BrushKey.Info400, FromRGB(0x80, 0xcc, 0xff));

            colors.TryAdd(BrushKey.Success100, FromRGB(0x99, 0xb4, 0x33));
            colors.TryAdd(BrushKey.Success200, FromRGB(0xb2, 0xcc, 0x4c));
            colors.TryAdd(BrushKey.Success300, FromRGB(0x76, 0x8b, 0x27));
            colors.TryAdd(BrushKey.Success400, FromRGB(0xdd, 0xe8, 0xb0));

            colors.TryAdd(BrushKey.Obsoleted100, FromRGB(0xca, 0x51, 0x00));
            colors.TryAdd(BrushKey.Obsoleted200, FromRGB(0xff, 0x66, 0x00));
            colors.TryAdd(BrushKey.Obsoleted300, FromRGB(0x99, 0x3d, 0x00));
            colors.TryAdd(BrushKey.Obsoleted400, FromRGB(0xff, 0x94, 0x4d));


            colors.TryAdd(BrushKey.SlateGray100, FromRGB(0x4f, 0x5b, 0x66));
            colors.TryAdd(BrushKey.SlateGray200, FromRGB(0x70, 0x80, 0x90));
            colors.TryAdd(BrushKey.SlateGray300, FromRGB(0x28, 0x2e, 0x34));
            colors.TryAdd(BrushKey.SlateGray400, FromRGB(0x9b, 0xa6, 0xb1));
        }

        /// <summary>
        /// 初始化高亮色
        /// </summary>
        /// <param name="colors">容器</param>
        protected abstract void InitializeBackgroundBrush(Dictionary<BrushKey, uint> colors);

        /// <summary>
        /// 初始化背景色
        /// </summary>
        /// <param name="colors">容器</param>
        protected virtual void InitializeHighlightBrush(Dictionary<BrushKey, uint> colors)
        {
            colors.TryAdd(BrushKey.HighlightA1, FromRGB(0xe5, 0xe9, 0xaf));
            colors.TryAdd(BrushKey.HighlightA2, FromRGB(0xd1, 0xd9, 0x72));
            colors.TryAdd(BrushKey.HighlightA3, FromRGB(0xbe, 0xc9, 0x36));
            colors.TryAdd(BrushKey.HighlightA4, FromRGB(0x98, 0xa1, 0x2b));
            colors.TryAdd(BrushKey.HighlightA5, FromRGB(0x72, 0x79, 0x20));

            colors.TryAdd(BrushKey.HighlightB1, FromRGB(0xff, 0xda, 0x96));
            colors.TryAdd(BrushKey.HighlightB2, FromRGB(0xff, 0xc2, 0x54));
            colors.TryAdd(BrushKey.HighlightB3, FromRGB(0xff, 0xab, 0x12));
            colors.TryAdd(BrushKey.HighlightB4, FromRGB(0xd4, 0x89, 0x00));
            colors.TryAdd(BrushKey.HighlightB5, FromRGB(0x96, 0x61, 0x00));

            colors.TryAdd(BrushKey.HighlightC1, FromRGB(0xbf, 0xb8, 0xe9));
            colors.TryAdd(BrushKey.HighlightC2, FromRGB(0x95, 0x89, 0xdb));
            colors.TryAdd(BrushKey.HighlightC3, FromRGB(0x6a, 0x5a, 0xcd));
            colors.TryAdd(BrushKey.HighlightC4, FromRGB(0x48, 0x36, 0xb3));
            colors.TryAdd(BrushKey.HighlightC5, FromRGB(0x35, 0x28, 0x84));
        }

        /// <summary>
        /// 初始化前景色
        /// </summary>
        /// <param name="colors">容器</param>
        protected abstract void InitializeForegroundBrush(Dictionary<BrushKey, uint> colors);

        /// <summary>
        /// 初始化适应色
        /// </summary>
        /// <param name="colors">容器</param>
        protected abstract void InitializeAdaptiveBrush(Dictionary<BrushKey, uint> colors);

        /// <summary>
        /// 初始化其他色
        /// </summary>
        /// <param name="colors">容器</param>
        protected virtual void InitializeOthersBrush(Dictionary<BrushKey, uint> colors)
        {

        }

        /// <summary>
        /// 保存颜色
        /// </summary>
        /// <returns>返回字符串数组。</returns>
        public string[] Save()
        {
            var colors = Colors.Select(x => $"{(uint)x.Key},{x.Value.ToString()}")
                               .ToArray();

            return colors;
        }

        /// <summary>
        /// 颜色池
        /// </summary>
        public Dictionary<BrushKey, uint> Colors { get; protected init; }
    }
}